package com.soup.lab.basic.keyable;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * 实现该接口的类都是可提取特征值的。
 * 返回的特征值相同，代表属于同一（类）事物。
 */
public interface Keyable {

    /**
     * 获取特征值
     * @return
     */
    String getKey();

    /**
     * 使用 JDK 动态代理组合目标类和 keyable，附魔 keyable 的功能。
     *
     * @param target
     * @param keyable
     * @param <T>
     * @return
     */
    static <T> T enchant(T target, Keyable keyable) {
        Class<?>[] interfaces = target.getClass().getInterfaces();
        Class<?>[] classes = Arrays.copyOf(interfaces, interfaces.length + 1);
        classes[classes.length - 1] = Keyable.class;
        return (T) Proxy.newProxyInstance(Keyable.class.getClassLoader(), classes, new KeyableInvocationHandler(target, keyable));
    }

    class KeyableInvocationHandler implements InvocationHandler {
        private final Object target;
        private final Keyable keyable;

        public KeyableInvocationHandler(Object target, Keyable keyable) {
            this.target = target;
            this.keyable = keyable;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if("getKey".equals(method.getName()) && method.getParameterCount() == 0) {
                return keyable.getKey();
            }
            return method.invoke(target, args);
        }
    }

}
